package com.ok.common.mqtt

import android.content.Context
import android.os.Handler
import android.os.Looper
import com.ok.common.utils.LogUtils
import info.mqtt.android.service.MqttAndroidClient
import org.eclipse.paho.client.mqttv3.DisconnectedBufferOptions
import org.eclipse.paho.client.mqttv3.IMqttActionListener
import org.eclipse.paho.client.mqttv3.IMqttDeliveryToken
import org.eclipse.paho.client.mqttv3.IMqttToken
import org.eclipse.paho.client.mqttv3.MqttCallback
import org.eclipse.paho.client.mqttv3.MqttCallbackExtended
import org.eclipse.paho.client.mqttv3.MqttConnectOptions
import org.eclipse.paho.client.mqttv3.MqttMessage

/**
 * Mqtt客户端
 */
class MqttClient private constructor() {

    private var mMqttAndroidClient: MqttAndroidClient? = null

    private var mMqttClientOption: MqttConnectOptions = MqttConnectOptions()

    private val mSubscribeTopics: MutableList<MqttTopic> = ArrayList()

    private var mMqttListener: MqttListener? = null

    private var mMqttConfig: MqttConfig? = null

    private var mHandler = Handler(Looper.getMainLooper())

    companion object {

        private const val TAG = "MqttClient"

        private val instance: MqttClient by lazy { MqttClient() }

        fun get(): MqttClient = instance

    }

    /**
     * 初始化Mqtt
     */
    fun init(
        context: Context, mqttConfig: MqttConfig
    ) {
        this.mMqttConfig = mqttConfig
        this.mMqttAndroidClient =
            MqttAndroidClient(context.applicationContext, mqttConfig.serverUrl, mqttConfig.clientId).apply {
                addCallback(mqttCallback)
                mMqttClientOption.apply {
                    isCleanSession = mqttConfig.isCleanSession
                    isAutomaticReconnect = mqttConfig.isAutomaticReconnect
                    connectionTimeout = mqttConfig.connectionTimeout
                    keepAliveInterval = mqttConfig.keepAliveInterval
                    maxInflight = mqttConfig.maxInflight
                    socketFactory = mqttConfig.mSSLSocketFactory
                    if (mqttConfig.userName.isNotBlank() && mqttConfig.password.isNotBlank()) {
                        userName = mqttConfig.userName
                        password = mqttConfig.password.toCharArray()
                    }
                }
            }
        mqttConfig.topics?.let {
            mSubscribeTopics.addAll(mqttConfig.topics)
        }
    }

    fun mqttConfig(): MqttConfig? = mMqttConfig

    /**
     * 连接
     */
    fun connect(listener: MqttListener) {
        mMqttListener = listener
        mMqttAndroidClient?.let {
            if (!isConnected()) it.connect(mMqttClientOption, null, iMqttActionListener)
        }
    }

    /**
     * 断开连接
     */
    fun disconnect() {
        mMqttAndroidClient?.disconnect()
    }

    /**
     * 释放资源
     */
    fun close() {
        mMqttAndroidClient?.close()
    }

    /**
     * 判断连接是否断开
     */
    fun isConnected(): Boolean {
        return mMqttAndroidClient?.isConnected() == true
    }

    /**
     * 订阅默认Topic.
     */
    private fun subscribeDefaultTopic() {
        subscribe(mSubscribeTopics)
    }

    /**
     * 订阅Topic
     */
    fun subscribe(mqttTopic: MqttTopic) {
        LogUtils.i(TAG, "MQTT：订阅主题：$mqttTopic")
        mMqttAndroidClient?.subscribe(mqttTopic.topic, mqttTopic.qos)
    }

    /**
     * 订阅Topic集合
     */
    fun subscribe(mqttTopics: MutableList<MqttTopic>) {
        if (mqttTopics.isEmpty()) {
            return
        }
        mqttTopics.forEach {
            subscribe(it)
        }
    }

    /**
     * 取消订阅默认Topic.
     */
    private fun unSubscribeDefaultTopic() {
        unSubscribe(mSubscribeTopics)
    }

    /**
     * 取消订阅Topic
     */
    fun unSubscribe(mqttTopic: MqttTopic) {
        LogUtils.i(TAG, "MQTT：取消订阅主题：$mqttTopic")
        mMqttAndroidClient?.unsubscribe(mqttTopic.topic)
    }

    /**
     * 取消订阅Topic集合
     */
    fun unSubscribe(mqttTopics: MutableList<MqttTopic>) {
        if (mqttTopics.isEmpty()) {
            return
        }
        mqttTopics.forEach {
            unSubscribe(it)
        }
    }

    /**
     * 发布消息
     *
     * @param msg
     * @param topic
     * @param qos
     * @param retained
     */
    fun publish(msg: String, topic: String, qos: Int = 2, retained: Boolean = false) {
        try {
            val message = MqttMessage()
            message.setPayload(msg.toByteArray())
            message.setQos(qos)
            message.setRetained(retained)
            mMqttAndroidClient?.publish(topic, message)
        } catch (e: Exception) {
            e.printStackTrace()
        }
    }

    /**
     * MQTT连接回调
     */
    private val iMqttActionListener: IMqttActionListener = object : IMqttActionListener {
        override fun onSuccess(asyncActionToken: IMqttToken) {
            LogUtils.i(TAG, "MQTT：connect success ")
        }

        override fun onFailure(arg0: IMqttToken, arg1: Throwable) {
            LogUtils.i(TAG, "MQTT：connect failed：$arg1")
            mHandler.post {
                mMqttListener?.connectFailed(arg0, arg1)
            }
        }
    }

    private val mqttCallback: MqttCallback = object : MqttCallbackExtended {

        override fun connectComplete(reconnect: Boolean, serverURI: String) {
            mHandler.post {
                mMqttListener?.connectSuccess(null, reconnect)
            }
            subscribeDefaultTopic()
            if (!reconnect) {
                //设置连接断开的缓冲配置
                val disconnectedBufferOptions = DisconnectedBufferOptions()
                disconnectedBufferOptions.isBufferEnabled = true
                disconnectedBufferOptions.setBufferSize(500)
                disconnectedBufferOptions.isPersistBuffer = false
                disconnectedBufferOptions.isDeleteOldestMessages = false
                mMqttAndroidClient?.setBufferOpts(disconnectedBufferOptions)
            } else {
                LogUtils.i(TAG, "MQTT：Reconnect Complete")
            }
        }

        override fun messageArrived(topic: String, message: MqttMessage) {
            val payload = String(message.payload)
            val details = "payload：$payload，qos：${message.qos}，retained：${message.isRetained}"
            LogUtils.i(TAG, "MQTT：收到消息：$details")
            mHandler.post {
                mMqttListener?.messageArrived(topic, payload, message.qos)
            }
        }

        override fun deliveryComplete(iMqttDeliveryToken: IMqttDeliveryToken) {
            LogUtils.i(TAG, "MQTT：deliveryComplete：")
            mHandler.post {
                mMqttListener?.deliveryComplete(iMqttDeliveryToken)
            }
        }

        override fun connectionLost(e: Throwable) {
            try {
                LogUtils.i(TAG, "MQTT：connectionLost")
                mHandler.post {
                    mMqttListener?.connectionLost(e)
                }
            } catch (e: Exception) {
            }
        }
    }

}